import { message } from "antd";

declare const MethodTypes: ["POST", "GET"];
type MethodType = typeof MethodTypes[number];

interface RequestOptions {
    method?: MethodType;
    body?: any;
    headers?: any;
    timeout?: number;
}

interface AjaxGolobalConfigInterface {
    headers?: any;

}

interface AjaxResponse {
    json: () => Promise<any>;
    text: string;
    ok: boolean;
    statusCode: number;
    xhr: XMLHttpRequest;
    header: (key:string) => string | null
}

interface AjaxInterface {
    config: AjaxGolobalConfigInterface;
    ajax: (url: string, options?: RequestOptions) => Promise<AjaxResponse>;
    get: (url: string, options?: RequestOptions) => Promise<AjaxResponse>;
    post: (url: string, options?: RequestOptions) => Promise<AjaxResponse>;
}

class RequestResponse implements AjaxResponse {
    xhr: XMLHttpRequest;
    statusCode: number;
    ok: boolean;
    text: string;
    json(): Promise<any> {
        return new Promise((reslove, reject) => {
            try {
                let json: any = JSON.parse(this.text);
                reslove(json);
            } catch (err) {
                reject(err);
            }
        })
    }
    header(key:string):string|null {
        return this.xhr.getResponseHeader(key);
    }
    constructor(xhr: XMLHttpRequest) {
        this.xhr =xhr;
        this.statusCode = xhr.status;
        this.text = xhr.responseText;
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
            this.ok = true;
        } else if(xhr.status === 403) {
            message.error("您当前未登录或登陆已过期");
            setTimeout(() => {
                window.location.replace("/index/user/login");
            }, 1000)
            this.ok = true;
        } else {
            this.ok = false;
        }
    }
}


class Ajax implements AjaxInterface {
    config: AjaxGolobalConfigInterface;
    ajax(url: string, options?: RequestOptions): Promise<AjaxResponse> {
        let _this = this;
        switch (options ? options.method : "") {
            case "GET":
                return _this.get(url, options ? options : {});
            case "POST":
                return _this.post(url, options ? options : {});
        }
        return Promise.reject("method error")
    };
    get(url: string, options?: RequestOptions): Promise<AjaxResponse> {
        return new Promise((resolve, reject) => {
            let xhr = new XMLHttpRequest();
            let each: string;
            for (each in (options as RequestOptions).body) {
                url += url.indexOf('?') === -1 ? "?" : "&";
                url = url + encodeURIComponent(each) + "=" + encodeURIComponent((options as RequestOptions).body[each]);
            };
            xhr.open("GET", url);
            if (this.config) {
                for (each in this.config.headers) {
                    xhr.setRequestHeader(each, this.config.headers[each]);
                }
            }

            if ((options as RequestOptions).timeout) {
                xhr.timeout = (options as RequestOptions).timeout as number;
            }
            xhr.send();
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    if (xhr.status !== 0) {
                        resolve(new RequestResponse(xhr))
                    } else {
                        reject("connet error!")
                    }
                }
            }
        });
    };
    post(url: string, options?: RequestOptions): Promise<AjaxResponse> {
        return new Promise((resolve, reject) => {
            let xhr = new XMLHttpRequest();
            let each: string;
            xhr.open("POST", url);
            if (this.config) {
                for (each in this.config.headers) {
                    xhr.setRequestHeader(each, this.config.headers[each]);
                }
            }

            for (each in (options as RequestOptions).headers) {
                xhr.setRequestHeader(each, (options as RequestOptions).headers[each]);
            }
            if ((options as RequestOptions).timeout) {
                xhr.timeout = (options as RequestOptions).timeout as number;
            }
            xhr.send((options as RequestOptions).body);
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    if (xhr.status !== 0) {
                        resolve(new RequestResponse(xhr))
                    } else {
                        reject("connect error!")
                    }
                }
            }
        });
    }
    constructor(config?: AjaxGolobalConfigInterface) {
        if (!config) {
            this.config = {};
        } else {
            this.config = config as AjaxGolobalConfigInterface;
        }

        this.ajax = this.ajax.bind(this);
    }
}

export default new Ajax()

